/*
 * jxUtils Project (2013, 2014)
 * 
 * by Denilson Edinaldo Pinto
 * 
 * LGPL
 * Copyright (C) 2014
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */
package org.jxUtils.system;

import java.awt.Component;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.print.PageFormat;
import java.awt.print.Printable;
import java.awt.print.PrinterException;
import java.awt.print.PrinterJob;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;

import javax.print.Doc;
import javax.print.DocFlavor;
import javax.print.DocPrintJob;
import javax.print.PrintException;
import javax.print.PrintService;
import javax.print.PrintServiceLookup;
import javax.print.SimpleDoc;
import javax.print.attribute.HashPrintRequestAttributeSet;
import javax.print.attribute.PrintRequestAttributeSet;
import javax.print.attribute.PrintServiceAttribute;
import javax.print.attribute.standard.JobName;
import javax.print.attribute.standard.PrinterName;

import org.jxUtils.i18n.I18N;

/**
 * @author Denilson Edinaldo Pinto
 * @porject jxUtils
 * @package org.jxUtils.system
 * @date 06/02/2013 - 22:18:46
 */
public final class PrintUtil {
	
	/**
	 * @param printServiceName
	 * @return {@link PrintService} or null
	 */
	public static PrintService getPrintService(final String printServiceName) {
	
		final PrintService[] services = getPrintServices();
		
		PrintServiceAttribute printServiceAttribute = null;
		
		String printerName = "";
		
		//
		for(final PrintService printService : services) {
			
			printServiceAttribute = printService.getAttribute(PrinterName.class);
			
			printerName = ((PrinterName)printServiceAttribute).getValue();
			
			//
			if(printerName.trim().toUpperCase().indexOf(printServiceName.trim().toUpperCase()) >= 0) {
				
				return printService;
			}
		}
		
		return null;
	}
	
	/**
	 * @return {@link PrintService}
	 */
	public static PrintService[] getPrintServices() {
	
		return PrintServiceLookup.lookupPrintServices(DocFlavor.SERVICE_FORMATTED.PRINTABLE, null);
	}
	
	/**
	 * @param component
	 * @throws PrinterException 
	 */
	public static void print(final Component component) throws PrinterException {
	
		Printable printable = new Printable() {
			
			@Override
			public int print(Graphics graphics, PageFormat pageFormat, int pageIndex) throws PrinterException {
			
				//
				if(pageIndex > 0) {
					
					return NO_SUCH_PAGE;
				}
				
				Graphics2D graphics2d = (Graphics2D) graphics;
				
				graphics2d.translate(pageFormat.getImageableX(), pageFormat.getImageableY());
				
				component.printAll(graphics);
				
				return PAGE_EXISTS;
			}
		};
		
		// 
		PrinterJob printerJob = PrinterJob.getPrinterJob();
		printerJob.setPrintable(printable);
		
		// 
		if(printerJob.printDialog()) {
			
			printerJob.print();
		}
	}
	
	/**
	 * @param file
	 * @throws PrintException
	 * @throws Exception
	 * @since Print file with default print service
	 */
	public static void print(final File file) throws PrintException, Exception {
	
		final HashPrintRequestAttributeSet printerAttributes = new HashPrintRequestAttributeSet();
		
		printerAttributes.add(new JobName(file.getName(), null));
		
		print(PrintServiceLookup.lookupDefaultPrintService(), file, printerAttributes);
	}
	
	/**
	 * @param file
	 * @param printerAttributes
	 * @throws PrintException
	 * @throws Exception
	 * @since Print file with default print service
	 */
	public static void print(final File file, final HashPrintRequestAttributeSet printerAttributes) throws PrintException, Exception {
	
		print(PrintServiceLookup.lookupDefaultPrintService(), file, printerAttributes);
	}
	
	/**
	 * @param file
	 * @param jobName
	 * @param printerAttributes
	 * @throws PrintException
	 * @throws Exception
	 * @since Print file with default print service
	 */
	public static void print(final File file, final String jobName, final PrintRequestAttributeSet printerAttributes) throws PrintException, Exception {
	
		print(PrintServiceLookup.lookupDefaultPrintService(), file, jobName, printerAttributes);
	}
	
	/**
	 * @param printService
	 * @param file
	 * @param printerAttributes
	 * @throws PrintException
	 * @throws Exception
	 */
	public static void print(final PrintService printService, final File file, final HashPrintRequestAttributeSet printerAttributes) throws PrintException, Exception {
	
		printerAttributes.add(new JobName(file.getName(), null));
		
		print(printService, new FileInputStream(file), DocFlavor.INPUT_STREAM.AUTOSENSE, printerAttributes);
		
	}
	
	/**
	 * @param printService
	 * @param file
	 * @param jobName
	 * @param printerAttributes
	 * @throws PrintException
	 * @throws Exception
	 */
	public static void print(final PrintService printService, final File file, final String jobName, final PrintRequestAttributeSet printerAttributes) throws PrintException, Exception {
	
		printerAttributes.add(new JobName(jobName, null));
		
		print(printService, new FileInputStream(file), DocFlavor.INPUT_STREAM.AUTOSENSE, printerAttributes);
		
	}
	
	/**
	 * @param printService
	 * @param printData
	 * @param docFlavor
	 * @param printerAttributes
	 * @throws PrintException
	 * @throws Exception
	 */
	public static void print(final PrintService printService, final Object printData, final DocFlavor docFlavor, final PrintRequestAttributeSet printerAttributes) throws PrintException, Exception {
	
		final SimpleDoc simpleDoc = new SimpleDoc(printData, docFlavor, null);
		
		final DocPrintJob printJob = printService.createPrintJob();
		
		printJob.print(simpleDoc, printerAttributes);
		
		//
		if(printData instanceof InputStream) {
			
			((InputStream)printData).close();
		}
	}
	
	/**
	 * @param printServiceName
	 * @param docFlavor
	 * @param source
	 * @throws PrintException
	 * @throws Exception
	 */
	public static void printText(final String printServiceName, final DocFlavor.STRING docFlavor, final String source) throws PrintException, Exception {
	
		final PrintService printService = getPrintService(printServiceName);
		
		//
		if(printService != null) {
			
			final DocPrintJob docPrintJob = printService.createPrintJob();
			
			final Doc doc = new SimpleDoc(source, docFlavor, null);
			
			docPrintJob.print(doc, null);
			
		}else {
			
			throw new Exception(I18N.system().printNotFound(printServiceName));
		}
	}
	
	/**
	 * @param printServiceName
	 * @param source
	 * @throws PrintException
	 * @throws Exception
	 */
	public static void printToZebra(final String printServiceName, final String source) throws PrintException, Exception {
	
		final PrintService printService = getPrintService(printServiceName);
		
		//
		if(printService != null) {
			
			final DocPrintJob docPrintJob = printService.createPrintJob();
			
			final byte[] codeInBytes = source.getBytes();
			
			final DocFlavor docFlavor = DocFlavor.BYTE_ARRAY.AUTOSENSE;
			
			final Doc doc = new SimpleDoc(codeInBytes, docFlavor, null);
			
			docPrintJob.print(doc, null);
			
		}else {
			
			throw new Exception(I18N.system().printNotFound(printServiceName));
		}
	}
}
